package cn.sylinx.horm.pool;

import java.util.Map;
import java.util.Optional;

import javax.sql.DataSource;

import cn.sylinx.horm.core.datasource.NamedDataSource;
import cn.sylinx.horm.dialect.DbType;
import cn.sylinx.horm.dialect.EnumDbType;
import cn.sylinx.horm.exception.HORMException;
import cn.sylinx.horm.util.ClassUtil;
import cn.sylinx.horm.util.GLog;
import cn.sylinx.horm.util.StrKit;

public enum DataSourceWrapperFactory {

    ;

    public static NamedDataSource buildDataSource(Map<String, Object> dsMap, Map<String, Object> extConfig) {
        String dbType = Optional.ofNullable(dsMap.get("dbtype")).orElse(EnumDbType.MYSQL.getValue()).toString();
        String pooltype = Optional.ofNullable(dsMap.get("pooltype")).orElse("").toString();
        String name = Optional.ofNullable(dsMap.get("name")).orElse("").toString();
        DataSource dataSource = new DefaultDataSourceSelector(dsMap, extConfig).select(selectPoolType(pooltype));
        if (dataSource == null) {
            throw new HORMException("缺少数据库连接池，请配置Beecp或Druid或TomcatJdbc或BoneCP或C3P0或dbcp或Hikari");
        }
        GLog.debug("dataSource:{} inited, config:{}", dataSource.getClass().getName(), dataSource);
        return NamedDataSource.create(dataSource, name, DbType.getDbType(dbType));
    }

    private static PoolType selectPoolType(String pooltype) {

        PoolType manuSelectPoolType = null;
        if (StrKit.isNotBlank(pooltype)) {
            manuSelectPoolType = PoolType.getPoolType(pooltype);
        }

        if (manuSelectPoolType != null) {
            if (isClassExist(manuSelectPoolType.getClassName())) {
                return manuSelectPoolType;
            }
        }
        if (isBeecpExist()) {
            return PoolType.Beecp;
        } else if (isHikariExist()) {
            return PoolType.Hikari;
        } else if (isDruidExist()) {// 检查cruid连接池是否存在
            return PoolType.Druid;
        } else if (isTomcatJdbcPoolExist()) {
            return PoolType.TomcatJdbc;
        } else if (isBoneCPExist()) {
            return PoolType.BoneCP;
        } else if (isC3P0Exist()) {
            return PoolType.C3P0;
        } else if (isDbcp2Exist()) {
            return PoolType.Dbcp2;
        } else if (isDbcpExist()) {
            return PoolType.Dbcp;
        }

        return null;
    }

    private static boolean isBeecpExist() {
        return isClassExist(PoolType.Beecp.getClassName());
    }

    private static boolean isDruidExist() {
        return isClassExist(PoolType.Druid.getClassName());
    }

    private static boolean isTomcatJdbcPoolExist() {
        return isClassExist(PoolType.TomcatJdbc.getClassName());
    }

    private static boolean isDbcp2Exist() {
        return isClassExist(PoolType.Dbcp2.getClassName());
    }

    private static boolean isDbcpExist() {
        return isClassExist(PoolType.Dbcp.getClassName());
    }

    private static boolean isC3P0Exist() {
        return isClassExist(PoolType.C3P0.getClassName());
    }

    private static boolean isBoneCPExist() {
        return isClassExist(PoolType.BoneCP.getClassName());
    }

    private static boolean isHikariExist() {
        return isClassExist(PoolType.Hikari.getClassName());
    }

    private static boolean isClassExist(String className) {
        return ClassUtil.isClassExist(className);
    }

}
